#pragma once

#include<iostream>
#include<pthread.h>
#include<queue>
#include<unistd.h>

// namespace zdl
// {
//     static const int gcp = 10;
//     template<class T>
//     class blockQueue
//     {
//     private:
//         std::queue<T> _q;
//         uint _cap; // 定义主容器的最大容量
//         pthread_cond_t _consumer_cond;   // 消费者条件变量
//         pthread_cond_t _productor_cond; // 生产者条件变量
//         pthread_mutex_t _mutex; // 实现互斥
//         int _c_wait_num;
//         int _p_wait_num;
//         bool isfull()
//         {
//             return _q.size() == _cap;
//         }
//         bool isempty()
//         {
//             return _q.size() == 0;
//         }
//     public:
//         blockQueue(int cap = gcp) : _cap(cap), 
//         _p_wait_num(0),
//         _c_wait_num(0)
//         {
//             // pthread_mutex_lock()
//             // zdl:: 在全局地区想要进行初始化，十分的简单，但是想要在局部的地区进行初始化，就需要是使用特定的函数菜有效果！！！            
//             pthread_mutex_init(&_mutex, nullptr);
//             pthread_cond_init(&_productor_cond, nullptr);
//             pthread_cond_init(&_consumer_cond, nullptr);

//         }
//         ~blockQueue()
//         {
//             pthread_mutex_destroy(&_mutex);
//             pthread_cond_destroy(&_productor_cond);
//             pthread_cond_destroy(&_consumer_cond);
//         }
//         void equeue(const T& data)
//         {
//             pthread_mutex_lock(&_mutex);
//             while (isfull()) // ??
//             {
//                 std::cout << "生产者进入等待" << std::endl;
//                 _p_wait_num++;
//                 pthread_cond_wait(&_productor_cond, &_mutex);
//                 // 我们在临界区等待是必然的（目前）
//                 // zdl:: wait 时我们是必然持有锁
//                 _p_wait_num--;
//             }
//             _q.emplace(data); // 生产
//             // zdl:: 做到这里就是一定有数据

//             if (_c_wait_num)
//             {
//                 pthread_cond_signal(&_consumer_cond);
//             }
//             pthread_mutex_unlock(&_mutex);
//         }
//         T pop()
//         {
//             pthread_mutex_lock(&_mutex);
//             while (isempty())
//             {
//                 std::cout << "消费者进入等待" << std::endl;
//                 ++_c_wait_num;
//                 pthread_cond_wait(&_consumer_cond, &_mutex);
//                 // 我们在临界区等待是必然的（目前）
//                 // zdl:: wait 时我们是必然持有锁
//                 --_c_wait_num;
//             }
//             auto x = _q.front(); _q.pop();

//             // zdl:: 走到了这里就是还有空间存在，所以此时我就缓刑相应的没事情干的生产者，然他继续生产！
//             pthread_cond_signal(&_productor_cond);
//             pthread_mutex_unlock(&_mutex);
//             return x;
//         }
//     };
    

    
// }

// version 2

#include"Mutex.hpp"
#include "cond.hpp"
namespace zdl
{
    using namespace LockModule;
    using namespace condMoudle;
    static const int gcp = 10;
    template<class T>
    class blockQueue
    {
    private:
        std::queue<T> _q;
        uint _cap; // 定义主容器的最大容量
        cond _consumer_cond;   // 消费者条件变量
        cond _productor_cond; // 生产者条件变量
        Mutex _mutex; // 实现互斥
        int _c_wait_num;
        int _p_wait_num;
        bool isfull()
        {
            return _q.size() == _cap;
        }
        bool isempty()
        {
            return _q.size() == 0;
        }
    public:
        blockQueue(int cap = gcp) : _cap(cap), 
        _p_wait_num(0),
        _c_wait_num(0)
        {

        }
        ~blockQueue()
        {

        }
        void equeue(const T& data)
        {
            LockGuard lockguard(_mutex);
            while (isfull()) // ??
            {
                std::cout << "生产者进入等待" << std::endl;
                _p_wait_num++;
                _productor_cond.wait(_mutex);
                // 我们在临界区等待是必然的（目前）
                // zdl:: wait 时我们是必然持有锁
                _p_wait_num--;

                std::cout << "生产者被叫醒。。。" << std::endl;
            }
            _q.emplace(data); // 生产
            // zdl:: 做到这里就是一定有数据

            if (_c_wait_num)
            {
                cout << "叫醒生产者..." <<endl;
                _consumer_cond.notify();
            }
        }
        T pop()
        {
            while (isempty())
            {
                LockGuard lockguard(_mutex);
                std::cout << "消费者进入等待" << std::endl;
                ++_c_wait_num;
                _consumer_cond.wait(_mutex);
                // 我们在临界区等待是必然的（目前）
                // zdl:: wait 时我们是必然持有锁
                --_c_wait_num;
            }
            auto x = _q.front(); _q.pop();

            // zdl:: 走到了这里就是还有空间存在，所以此时我就缓刑相应的没事情干的生产者，然他继续生产！
            if (_p_wait_num)
            {
                std::cout << "叫醒生产者..." << std::endl;
                _productor_cond.notify();
            }
            return x;
        }
    };
    

    
}